"""
The code for this class was copied from ASPN Python Cookbook. The entry still exists, but the code does not.
No license was provided so it is safe to assume this code falls under the Python License.
"""
import types
import string
import socket

from coffeetalk.protocol import ioelement
from coffeetalk.protocol.iotypes import defaulttype

       
class IPAddress():
    """
    Store an IP addresss. Pre-compute the network, host, and broadcast and
    store that as well.
    
    ipaddress = IPaddr(address, [mask])
    supply an address as either integer or string. A netmask may
    optionally be supplied. It defaults to a classful mask appropriate for its
    class. the netmask may be supplied as integer, dotted quad, or slash (e.g.
    /24) notation.
    
    Exports 'string' method that returns IP addresses as dotted quad string.
    
    Raises ValueError if the string representation is malformed, or is not an
    integer.
    """

    def __init__(self, address,mask=None):
        # determine input type and convert if necessary
        if type(address) == types.StringType:
            self.address = self.dqtoi(socket.gethostbyname(address))
        elif type(address) == types.IntType:
            self.address = address
        else:
            print 'raising ValueError'
            raise ValueError
        
        # handle the optional mask parameter. Default to classful mask.
        if mask == None:
            if self.address & 0x80000000 == 0:
                self.mask = 0xff000000
            elif self.address & 0x40000000 == 0:
                self.mask = 0xffff0000
            else:
                self.mask = 0xffffff00
        elif type(mask) == types.StringType:
            if mask[0] == '/':
                bits = int(mask[1:])
                if bits <= 32 and bits > 0:
                    self.mask = 0xffffffff << (32 - bits)
                else:
                    raise ValueError
            else:
                self.mask = self.dqtoi(mask)
        elif type(mask) == types.IntType:
            self.mask = mask
        else:
            raise ValueError
        # compute and store network, host, and broadcast address
        self.network = self.address & self.mask

        # check for host specific address
        if self.mask == 0xffffffff:
            self.host = self.address
            self.broadcast = 0xffffffff
        else:
            self.host = self.address & (~self.mask)
            self.broadcast = self.address | (~self.mask)
    
    def __repr__(self):
        return str(self.itodq(self.address)) + '/' + str(self.itodq(self.mask))
        
    def __lt__(self,other):
        
        if self.network < other.network:
            return True
        else:
            return False

    def __gt__(self,other):
    
        if self.broadcast > other.broadcast:
            return True
        else:
            return False
      
    def __eq__(self,other):
    
        if self.network == other.network and self.broadcast == other.broadcast and self.address == other.address:
            return True
        else:
            return False

    def __ne__(self,other):

        if self == other:
            return False
        else:
            return True

    def dqtoi(self,dq):
        "Return an integer value given an IP address as dotted-quad string."
        octets = string.split(dq, ".")
        if len(octets) != 4:
            raise ValueError
        for octet in octets:
            if int(octet) > 255:
                raise ValueError
        return (int(octets[0]) << 24) + \
                (int(octets[1]) << 16) + \
                (int(octets[2]) << 8) + \
                (int(octets[3]))
  
    def itodq(self,intval):
            "Return a dotted-quad string given an integer. "
            return "%u.%u.%u.%u" % ((intval >> 24) & 0x000000ff,
                                    ((intval & 0x00ff0000) >> 16),
                                    ((intval & 0x0000ff00) >> 8),
                                    (intval & 0x000000ff))

class IPv4(defaulttype.DefaultType):
    
    _type = '[IPv4]'
    ip = IPAddress('0.0.0.0')
    value = ''
    def __init__(self,name=None,value=None):
        defaulttype.DefaultType.__init__(self,name=name)
        address,mask = None, None
        if value.find('/') > -1:
            address,mask = value.split('/',1)
        else:
            address = value
        self.ip = IPAddress(address=address,mask=mask)
        self.value = str(self.ip)
        
    def _to_element(self):
        return ioelement.IOElement(self.name,{'type':'[IPv4]','value':self.value})
    
    def __str__(self):
        return str(self._to_element())

if __name__ == '__main__':
    """These tests need to be redone. Ick"""
    ip = IPAddress('12.34.56.2','255.255.255.240')
    otherip = IPAddress('12.34.56.3','255.255.255.240')
    
    print 'First IP: ' + str(ip) + ',' + str(ip.itodq(ip.network)) + ',' + str(ip.itodq(ip.broadcast))
    print 'Second IP: ' + str(otherip) + ',' + str(otherip.itodq(otherip.network)) + ',' + str(otherip.itodq(otherip.broadcast))
    
    print str(ip) + ' < ' + str(otherip) + ' : ',
    print str(ip < otherip)
    
    print str(ip) + ' > ' + str(otherip) + ' : ',
    print str(ip > otherip)
    
    print str(ip) + ' == ' + str(otherip) + ' : ',
    print str(ip == otherip)
    
    print str(ip) + ' != ' + str(otherip) + ' : ',
    print str(ip != otherip)
    